package aes.client;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Observable;
import java.util.Observer;

import javax.swing.*;
import javax.swing.border.*;

import javax.swing.filechooser.FileFilter;

import common.*;

public class ManualExamExecutionFormUI extends JPanel implements ActionListener, Observer {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7298619844514641647L;
	private ClientUI ui;
	private Client c;
	
	private JLabel lblAesTitle;
	private JButton btnBack;
	private JButton btnFinish;
	private JLabel lblTime;
	
	private Timer timer;
	private int avaliableTime = 0;
	private JButton btnDownload;
	
	@SuppressWarnings("unused")
	private int studentId;
	private StudentExam se;
	
	private final JFileChooser afc;
	private File selectedfile = null;
	private boolean isReport = false;

	/**
	 * Constructor
	 * @param c Client object reference
	 * @param ui ClientUI object reference
	 */
	public ManualExamExecutionFormUI(Client c,ClientUI ui){
		super();
		this.c = c;
		this.ui = ui;
		
		c.addObserver(this);
		GridBagLayout gridBagLayout = new GridBagLayout();
		setLayout(gridBagLayout);
		
		JPanel panel = new JPanel();
		panel.setBorder(new LineBorder(new Color(0, 0, 0), 2, true));
		panel.setPreferredSize(new Dimension(600,400));
		panel.setSize(new Dimension(600,400));
		
		GridBagConstraints gbc_panel = new GridBagConstraints();
		gbc_panel.fill = GridBagConstraints.HORIZONTAL;
		gbc_panel.insets = new Insets(5, 0, 5, 0);
		gbc_panel.gridx = 0;
		gbc_panel.gridy = 0;
		add(panel,gbc_panel);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{70, 330};
		gbl_panel.columnWeights = new double[]{1.0, 1.0};
		panel.setLayout(gbl_panel);
		
		lblAesTitle = new JLabel("Exam Execution");
		lblAesTitle.setHorizontalAlignment(SwingConstants.CENTER);
		lblAesTitle.setBounds(7, 10, 70, 17);
		lblAesTitle.setFont(new Font("Tahoma", Font.BOLD, 14));
		
		GridBagConstraints gbc_lblAesTitle = new GridBagConstraints();
		gbc_lblAesTitle.gridwidth = 2;
		gbc_lblAesTitle.fill = GridBagConstraints.BOTH;
		gbc_lblAesTitle.insets = new Insets(5, 0, 5, 0);
		gbc_lblAesTitle.gridx = 0;
		gbc_lblAesTitle.gridy = 0;
		panel.add(lblAesTitle, gbc_lblAesTitle);
		
		lblTime = new JLabel("Time left: 00:00:00");
		GridBagConstraints gbc_lblTime = new GridBagConstraints();
		gbc_lblTime.anchor = GridBagConstraints.EAST;
		gbc_lblTime.insets = new Insets(0, 0, 5, 10);
		gbc_lblTime.gridx = 1;
		gbc_lblTime.gridy = 1;
		panel.add(lblTime, gbc_lblTime);
		
		btnBack = new JButton("Back");
		btnBack.addActionListener(this);
		
		btnDownload = new JButton("Download Exam");
		btnDownload.addActionListener(this);
		btnDownload.setIcon(new ImageIcon(ManualExamExecutionFormUI.class.getResource("/aes/client/images/Download.png")));
		GridBagConstraints gbc_btnDownload = new GridBagConstraints();
		gbc_btnDownload.gridwidth = 2;
		gbc_btnDownload.insets = new Insets(0, 10, 5, 0);
		gbc_btnDownload.gridx = 0;
		gbc_btnDownload.gridy = 4;
		panel.add(btnDownload, gbc_btnDownload);
		btnBack.setIcon(new ImageIcon(ExamExecutionFormUI.class.getResource("/aes/client/images/back.png")));
		GridBagConstraints gbc_btnBack = new GridBagConstraints();
		gbc_btnBack.anchor = GridBagConstraints.WEST;
		gbc_btnBack.insets = new Insets(0, 10, 0, 5);
		gbc_btnBack.gridx = 0;
		gbc_btnBack.gridy = 8;
		panel.add(btnBack, gbc_btnBack);
		
		btnFinish = new JButton("Finish");
		btnFinish.addActionListener(this);
		btnFinish.setIcon(new ImageIcon(ExamExecutionFormUI.class.getResource("/aes/client/images/Save.png")));
		GridBagConstraints gbc_btnFinish = new GridBagConstraints();
		gbc_btnFinish.insets = new Insets(0, 0, 0, 10);
		gbc_btnFinish.anchor = GridBagConstraints.EAST;
		gbc_btnFinish.gridx = 1;
		gbc_btnFinish.gridy = 8;
		panel.add(btnFinish, gbc_btnFinish);
				
		// Initialize timer.
		timer=new Timer(1000, this);
		
		afc = new JFileChooser();
		afc.setFileFilter(new FileFilter() {
			public boolean accept(File f) {
				return f.getName().toLowerCase().endsWith(".doc")
						|| f.isDirectory() || f.getName().toLowerCase().endsWith(".docx");
			}

			public String getDescription() {
				return "Word Files";
			}
		});
	}
	
	/**
	 * Load exam
	 * @param code Exam code
	 * @param studentId Student Id
	 */
	public void loadExam(String code, int studentId) {
		this.studentId = studentId;
		btnDownload.setVisible(false);
		CommandMessage msg = new CommandMessage(CommandMessage.GET_STUDENT_EXAM,new Object[] {code, studentId});
		try {
			c.sendToServer(msg);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	
	/**
	 * Update clock
	 */
	@SuppressWarnings("static-access")
	private void UpdateClock() {
		if (ui.getUser() instanceof Student) {
			int seconds = avaliableTime % 60;
			int minutes = (avaliableTime / 60) % 60;
			int hours = avaliableTime / 3600;
			
			lblTime.setText("Time left: " + hours + ":" + String.format("%02d",minutes) + ":" + String.format("%02d", seconds));
			lblTime.setForeground((avaliableTime < 60)? Color.RED : Color.BLACK);
			
			if (avaliableTime < 1) {
				// Late.
				ui.ShowMessageBox("Message", "Your time has gone.", JOptionPane.INFORMATION_MESSAGE);
				
				// Go back.
				ui.ShowLastScreen();
				timer.stop();
				timer.removeActionListener(this);
				timer = null;
			}
		}
	}
	
	/**
	 * Send answers to the server
	 */
	@SuppressWarnings("static-access")
	private void SubmitAnswers(boolean hasFinished) {
		// Choose & read file.
		if (afc.showOpenDialog(ui) == JFileChooser.APPROVE_OPTION) {
			selectedfile = afc.getSelectedFile();
			byte[] data;
			try {
				FileInputStream fin = new FileInputStream(selectedfile);
				data = new byte[(int)selectedfile.length()];

				fin.read(data);
				fin.close();
				((ManualExamExecution)se.getExam()).setAnswersFileData(data);
			}
			catch(FileNotFoundException ex1)
			{
				ui.ShowMessageBox("ERROR", "Answers file not found", JOptionPane.ERROR_MESSAGE);
				return;
			}
			catch(IOException ioe)
			{
				ui.ShowMessageBox("ERROR", "Can't read answers file", JOptionPane.ERROR_MESSAGE);
				return;
			}
			
			CommandMessage msg = new CommandMessage(CommandMessage.SUBMIT_STUDENT_EXAM,new Object[] {se, hasFinished});
			try {
				c.sendToServer(msg);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} 
		else {
			ui.ShowMessageBox("ERROR", "No answers file was choosen", JOptionPane.ERROR_MESSAGE);
		}
	}
	
	/**
	 * Server message received event handler
	 */
	@SuppressWarnings("static-access")
	@Override
	public void update(Observable o, Object arg) {
		if (arg instanceof CommandMessage) {
			CommandMessage ms=(CommandMessage)arg;
			if (ms.getCommand().equals(CommandMessage.ACKNOWLEDGE_MESSAGE) && ((String)ms.getParams()[0]).equals(CommandMessage.GET_STUDENT_EXAM)) {
				if (ms.getParams()[1] == null) {
					// Not found.
					ui.ShowLastScreen();
					timer.stop();
					timer.removeActionListener(this);
					timer = null;
				}
				else {
					// Exam loaded.
					se = (StudentExam)ms.getParams()[1];
					btnDownload.setVisible(true);
					if (se.getTimeFinished() != null) {
						btnFinish.setVisible(false);
						lblAesTitle.setText("Grade: " + se.getGrade());
					}
					if (se.isApproved()) {
						// Student exam report.
						btnFinish.setVisible(false);
						lblAesTitle.setText("Grade: " + se.getGrade());
						lblTime.setVisible(false);
						isReport = true;
					}
					else {
						timer.stop();
						avaliableTime = se.getExam().getActualTime();
						timer.start();
						UpdateClock();
					}
				}
			}
			else if (ms.getCommand().equals(CommandMessage.ACKNOWLEDGE_MESSAGE) && ((String)ms.getParams()[0]).equals(CommandMessage.SUBMIT_STUDENT_EXAM)) {
				int grade = (ms.getParams()[1] == null)? -1 : Integer.parseInt(ms.getParams()[1].toString());
				if (grade < 0) {
					ui.ShowMessageBox("Error", "Can't submit your answers", JOptionPane.ERROR_MESSAGE);
				}
				else {
					ui.ShowMessageBox("Message", "Your answers were saved successfully.", JOptionPane.INFORMATION_MESSAGE);
					ui.ShowLastScreen();
					timer.stop();
					timer.removeActionListener(this);
					timer = null;
				}
			}
			else if (ms.getCommand().equals(CommandMessage.LOCK_EXAM_EXECUTION)) {
				String code = ms.getParams()[0].toString();
				if (se.getExam().getCode().equals(code) && timer.isRunning()) {
					// Exam was locked. 
					c.deleteObserver(this);
					// Stop timer.
					timer.stop();
					timer.removeActionListener(this);
					timer = null;
					// Submit answers.
					SubmitAnswers(false);
					// Inform user.
					ui.ShowMessageBox("Message", "Exam was locked.", JOptionPane.INFORMATION_MESSAGE);
					ui.ShowLastScreen();
				}
			}
			else if (ms.getCommand().equals(CommandMessage.ACCEPT_OR_REJECT_ADDITIONAL_TIME)) {
				String code = ms.getParams()[1].toString();
				int additionalTime = Integer.parseInt(ms.getParams()[0].toString());
				if (se.getExam().getCode().equals(code) && timer.isRunning()) {
					avaliableTime += additionalTime * 60;
					ui.ShowMessageBox("Message", "You have additional " + additionalTime + " minutes to solve the exam.", JOptionPane.INFORMATION_MESSAGE);
				}
			}
		}
	}

	/**
	 * Action performed event handler
	 */
	@SuppressWarnings("static-access")
	@Override
	public void actionPerformed(ActionEvent arg0) {
		if (arg0.getSource().equals(btnBack)) {
			// Back.
			ui.ShowLastScreen();
		}
		else if (arg0.getSource().equals(btnDownload)) {
			// Download file.
			if (se == null || se.getExam() == null)
				return;
			ManualExamExecution me = (ManualExamExecution) se.getExam();
			JFileChooser chooser = new JFileChooser(); 
			chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			chooser.setAcceptAllFileFilterUsed(false);
			if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { 
				// Store file.
				try {
					FileOutputStream fos;
					if (!isReport) {
						fos = new FileOutputStream(chooser.getSelectedFile() + "\\" + me.getFileName());
						fos.write(me.getFileData());
						fos.close();
						ui.ShowMessageBox("Message", "File (" + me.getFileName() + ") was saved.", JOptionPane.INFORMATION_MESSAGE);
					}
					else {
						fos = new FileOutputStream(chooser.getSelectedFile() + "\\Answer_" + me.getFileName());
						fos.write(me.getAnswersFileData());
						fos.close();
						ui.ShowMessageBox("Message", "File (" + chooser.getSelectedFile() + "\\Answer_" + me.getFileName() + ") was saved.", JOptionPane.INFORMATION_MESSAGE);
					}
				}
				catch(FileNotFoundException ex) {
					ui.ShowMessageBox("Error", "FileNotFoundException : " + ex, JOptionPane.ERROR_MESSAGE);
				}
				catch(IOException ioe) {
					ui.ShowMessageBox("Error", "IOException : " + ioe, JOptionPane.ERROR_MESSAGE);
				}
			}
		}
		else if (arg0.getSource().equals(btnFinish)) {
			// Submit answers.
			SubmitAnswers(true);
		}
		else if (arg0.getSource().equals(timer)) {
			// Timer tick event occured.
			avaliableTime--;
			UpdateClock();
		}
	}

}
